import {Injectable, Injector} from '@angular/core';
import {HttpInterceptor, HttpEvent, HttpHandler, HttpRequest, HttpErrorResponse} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {catchError, map} from 'rxjs/operators';
import {AuthService} from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private auth: AuthService;

  constructor(
    private injector: Injector
  ) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.auth = this.injector.get(AuthService);
    // 如果cookie中有token，且不是获取token的请求，则在header中加入token信息
    const token = this.auth.getAuth();
    if (token) {
      req = this.setToken(req, token.access_token);
    }
    // 继续执行
    return next.handle(req).pipe(
      map(res => {
        return res;
      }),
      catchError(error => {
        if (error instanceof HttpErrorResponse) {
          switch (error.status) {
            case 400 :
              return this.handler401Error(req, next, error);
            case 401:
              return this.handler401Error(req, next, error);
            default:
              return Observable.throw(error);
          }
        } else {
          return Observable.throw(error);
        }
      })
    );
  }

  /**
   * 权限错误
   * @param {HttpRequest<any>} req
   * @param {HttpHandler} next
   * @param error
   * @returns {Observable<HttpEvent<any>>}
   */
  handler401Error(req: HttpRequest<any>, next: HttpHandler, error: any): Observable<HttpEvent<any>> {
    return this.logout(error);
  }

  /**
   * 在请求头中加入token
   * @param {HttpRequest<any>} req
   * @param {string} token
   * @returns {HttpRequest<any>}
   */
  setToken(req: HttpRequest<any>, token: string): HttpRequest<any> {
    return req.clone({
      setHeaders: {
        'Authorization': `${token}`
      }
    });
  }

  /**
   * 错误的时候返回登陆页面
   * @param error
   * @returns {Observable<HttpEvent<any>>}
   */
  logout(error: any): Observable<HttpEvent<any>> {
    this.auth.logout();
    return Observable.throw(error);
  }
}
